package eu.irreality.dai.ui.keyboard;

import java.io.File;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import eu.irreality.dai.util.xml.DOMUtils;

public class ActionMapping
{

    private static String MAPPING_FILE = "keymap.xml";

    private KeyDescriptor keyStroke;
    private String stateName;
    private String actionName;

    private ActionMapping(KeyDescriptor stroke, String stateName,
	    String actionName)
    {
	this.keyStroke = stroke;
	this.stateName = stateName;
	this.actionName = actionName;
    }

    private static ActionMapping fromXML(Element e)
    {
	if (!e.hasAttribute("keyStroke"))
	    System.err.println("map element missing keyStroke attribute");
	String keyStrokeString = e.getAttribute("keyStroke");
	if (!e.hasAttribute("gameState"))
	    System.err.println("map element missing gameState attribute");
	String stateName = e.getAttribute("gameState");
	if (!e.hasAttribute("action"))
	    System.err.println("map element missing action attribute");
	String actionName = e.getAttribute("action");
	KeyDescriptor stroke = new KeyDescriptor(keyStrokeString);
	return new ActionMapping(stroke, stateName, actionName);
    }

    public static List<ActionMapping> readMappings()
	    throws TransformerException
    {
	InputStream is = ActionMapping.class.getClassLoader()
		.getResourceAsStream(MAPPING_FILE);
	Transformer t = TransformerFactory.newInstance().newTransformer();
	Source s = new StreamSource(is);
	DOMResult r = new DOMResult();
	t.transform(s, r);
	Node mappingsNode = ((Document) r.getNode()).getFirstChild();
	NodeList theMappings = DOMUtils.getDirectChildrenElementsByTagName(
		mappingsNode, "map");
	LinkedList<ActionMapping> result = new LinkedList<ActionMapping>();
	for (int i = 0; i < theMappings.getLength(); i++)
	{
	    Element mappingNode = (Element) theMappings.item(i);
	    ActionMapping mapping = fromXML(mappingNode);
	    result.add(mapping);
	}
	return result;
    }

    public static void writeMappings(List<ActionMapping> mappings)
	    throws ParserConfigurationException, TransformerException
    {
	File f = new File(MAPPING_FILE);

	Document d = DocumentBuilderFactory.newInstance().newDocumentBuilder()
		.newDocument();
	Element e = d.createElement("keymap");
	d.appendChild(e);
	for (ActionMapping mapping : mappings)
	{
	    e.appendChild(mapping.toXML(d));
	}
	Transformer t = TransformerFactory.newInstance().newTransformer();
	t.setOutputProperty(OutputKeys.INDENT, "yes");
	Source s = new DOMSource(d);
	Result r = new StreamResult(f);
	t.transform(s, r);
    }

    private Element toXML(Document d)
    {
	Element e = d.createElement("map");
	e.setAttribute("keyStroke", keyStroke.toString());
	e.setAttribute("gameState", stateName);
	e.setAttribute("action", actionName);
	return e;
    }

    public KeyDescriptor getKeyDescriptor()
    {
	return keyStroke;
    }

    public String getStateName()
    {
	return stateName;
    }

    public String getActionName()
    {
	return actionName;
    }

    /*
     * public void mapAction(int modifier, int keyCode, GameState state,
     * ActionFactory factory)
     */
}
